package com.ukefu.webim.service.task;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import com.ukefu.core.UKDataContext;
import com.ukefu.util.UKTools;
import com.ukefu.util.client.NettyClients;
import com.ukefu.util.es.SearchTools;
import com.ukefu.util.es.UKDataBean;
import com.ukefu.util.freeswitch.model.CallCenterAgent;
import com.ukefu.webim.service.acd.ServiceQuene;
import com.ukefu.webim.service.cache.CacheHelper;
import com.ukefu.webim.service.es.OnlineSimpleRepository;
import com.ukefu.webim.service.impl.CallOutQuene;
import com.ukefu.webim.service.repository.AgentServiceRepository;
import com.ukefu.webim.service.repository.AgentUserRepository;
import com.ukefu.webim.service.repository.AgentUserTaskRepository;
import com.ukefu.webim.service.repository.BlackListRepository;
import com.ukefu.webim.service.repository.CallOutNamesRepository;
import com.ukefu.webim.service.repository.ChatMessageRepository;
import com.ukefu.webim.service.repository.JobDetailRepository;
import com.ukefu.webim.util.OnlineUserUtils;
import com.ukefu.webim.util.router.OutMessageRouter;
import com.ukefu.webim.util.server.message.ChatMessage;
import com.ukefu.webim.web.model.AgentService;
import com.ukefu.webim.web.model.AgentStatus;
import com.ukefu.webim.web.model.AgentUser;
import com.ukefu.webim.web.model.AgentUserTask;
import com.ukefu.webim.web.model.BlackEntity;
import com.ukefu.webim.web.model.CallOutNames;
import com.ukefu.webim.web.model.JobDetail;
import com.ukefu.webim.web.model.MessageOutContent;
import com.ukefu.webim.web.model.OnlineUser;
import com.ukefu.webim.web.model.SessionConfig;

@Configuration
@EnableScheduling
public class WebIMTask {
	
	@Autowired
	private AgentUserTaskRepository agentUserTaskRes ;
	
	@Autowired
	private AgentUserRepository agentUserRes ;
	
	@Autowired
	private AgentServiceRepository agentServiceRes ;
	
	@Autowired
	private AgentServiceRepository agentServiceRepository;
	
	@Autowired
	private JobDetailRepository jobDetailRes ;
	

	@Autowired
	private OnlineSimpleRepository onlineUserRes ;
	
	@Autowired
	private BlackListRepository blackListRes ;
	
	@Scheduled(fixedDelay= 5000) // 每5秒执行一次
    public void task() {
		List<SessionConfig> sessionConfigList = ServiceQuene.initSessionConfigList() ;
		if(sessionConfigList!=null && sessionConfigList.size() > 0 && UKDataContext.getContext() != null && UKDataContext.needRunTask()){
			for(SessionConfig sessionConfig : sessionConfigList) {
				if(sessionConfig.isSessiontimeout()){		//设置了启用 超时提醒
					List<AgentUserTask> agentUserTask = agentUserTaskRes.findByLastmessageLessThanAndStatusAndOrgi(UKTools.getLastTime(sessionConfig.getTimeout()) , UKDataContext.AgentUserStatusEnum.INSERVICE.toString() , sessionConfig.getOrgi()) ;
					for(AgentUserTask task : agentUserTask){		// 超时未回复
						AgentUser agentUser = (AgentUser) CacheHelper.getAgentUserCacheBean().getCacheObject(task.getUserid(), UKDataContext.SYSTEM_ORGI);
						if(agentUser!=null && agentUser.getAgentno()!=null){
							AgentStatus agentStatus = (AgentStatus) CacheHelper.getAgentStatusCacheBean().getCacheObject(agentUser.getAgentno(), task.getOrgi()) ;
							task.setAgenttimeouttimes(task.getAgenttimeouttimes()+1);
							if(agentStatus!=null && (task.getWarnings()==null || task.getWarnings().equals("0"))){
								task.setWarnings("1");
								task.setWarningtime(new Date());
								
								//发送提示消息
								processMessage(sessionConfig, sessionConfig.getTimeoutmsg() , agentStatus.getUsername(),agentUser , agentStatus , task);
								agentUserTaskRes.save(task) ;
							}else if(sessionConfig.isResessiontimeout() && agentStatus!=null && task.getWarningtime()!=null && UKTools.getLastTime(sessionConfig.getRetimeout()).after(task.getWarningtime())){	//再次超时未回复
								/**
								 * 设置了再次超时 断开
								 */
								processMessage(sessionConfig, sessionConfig.getRetimeoutmsg() , sessionConfig.getServicename() , agentUser , agentStatus , task);
								try {
									ServiceQuene.serviceFinish(agentUser, task.getOrgi() , UKDataContext.EndByType.TIMEOUT.toString() , false);
								} catch (Exception e) {
									e.printStackTrace();
								}
							}
						}
					}
				}else if(sessionConfig.isResessiontimeout()){	//未启用超时提醒，只设置了超时断开
					List<AgentUserTask> agentUserTask = agentUserTaskRes.findByLastmessageLessThanAndStatusAndOrgi(UKTools.getLastTime(sessionConfig.getRetimeout()) , UKDataContext.AgentUserStatusEnum.INSERVICE.toString() , sessionConfig.getOrgi()) ;
					for(AgentUserTask task : agentUserTask){		// 超时未回复
						AgentUser agentUser = (AgentUser) CacheHelper.getAgentUserCacheBean().getCacheObject(task.getUserid(), UKDataContext.SYSTEM_ORGI);
						if(agentUser!=null){
							AgentStatus agentStatus = (AgentStatus) CacheHelper.getAgentStatusCacheBean().getCacheObject(agentUser.getAgentno(), task.getOrgi()) ;
							if(agentStatus!=null && task.getWarningtime()!=null && UKTools.getLastTime(sessionConfig.getRetimeout()).after(task.getWarningtime())){	//再次超时未回复
								/**
								 * 设置了再次超时 断开
								 */
								processMessage(sessionConfig, sessionConfig.getRetimeoutmsg() , agentStatus.getUsername(), agentUser , agentStatus , task);
								try {
									ServiceQuene.serviceFinish(agentUser, task.getOrgi() , UKDataContext.EndByType.TIMEOUT.toString() , false);
								} catch (Exception e) {
									e.printStackTrace();
								}
							}
						}
					}
				}
				if(sessionConfig.isQuene()){	//启用排队超时功能，超时断开
					List<AgentUserTask> agentUserTask = agentUserTaskRes.findByLogindateLessThanAndStatusAndOrgi(UKTools.getLastTime(sessionConfig.getQuenetimeout()) , UKDataContext.AgentUserStatusEnum.INQUENE.toString() , sessionConfig.getOrgi()) ;
					for(AgentUserTask task : agentUserTask){		// 超时未回复
						AgentUser agentUser = agentUserRes.findByIdAndOrgi(task.getId(), task.getOrgi()) ;
						if(agentUser!=null){
							/**
							 * 设置了超时 断开
							 */
							processMessage(sessionConfig, sessionConfig.getQuenetimeoutmsg() , sessionConfig.getServicename(), agentUser , null , task);
							try {
								ServiceQuene.serviceFinish(agentUser, task.getOrgi() , UKDataContext.EndByType.QUEUE.toString() , false);
								CacheHelper.getAgentUserCacheBean().delete(agentUser.getUserid(), UKDataContext.SYSTEM_ORGI);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}
				if(sessionConfig.isServicetimeoutlimit()){	//启用会话清理功能
					List<AgentUserTask> agentUserTask = agentUserTaskRes.findByEndtimeLessThanAndStatusAndOrgi(UKTools.getLastTime(sessionConfig.getServicetimeout()) , UKDataContext.AgentUserStatusEnum.END.toString() , sessionConfig.getOrgi()) ;
					for(AgentUserTask task : agentUserTask){		// 超时未回复
						agentUserTaskRes.delete(task);
					}
				}
			}
		}
	}
	
	@Scheduled(fixedDelay= 5000) // 每5秒执行一次
    public void agent() {
		List<SessionConfig> sessionConfigList = ServiceQuene.initSessionConfigList() ;
		if(sessionConfigList!=null && sessionConfigList.size() > 0 && UKDataContext.getContext() != null && UKDataContext.needRunTask()){
			for(SessionConfig sessionConfig : sessionConfigList) {
				sessionConfig = ServiceQuene.initSessionConfig(sessionConfig.getOrgi()) ;
				if(sessionConfig!=null && UKDataContext.getContext() != null && sessionConfig.isAgentreplaytimeout()){
					List<AgentUserTask> agentUserTask = agentUserTaskRes.findByLastgetmessageLessThanAndStatusAndOrgi(UKTools.getLastTime(sessionConfig.getAgenttimeout()) , UKDataContext.AgentUserStatusEnum.INSERVICE.toString() , sessionConfig.getOrgi()) ;
					for(AgentUserTask task : agentUserTask){		// 超时未回复
						AgentUser agentUser = (AgentUser) CacheHelper.getAgentUserCacheBean().getCacheObject(task.getUserid(), UKDataContext.SYSTEM_ORGI);
						if(agentUser!=null){
							AgentStatus agentStatus = (AgentStatus) CacheHelper.getAgentStatusCacheBean().getCacheObject(agentUser.getAgentno(), task.getOrgi()) ;
							if(agentStatus!=null && ( (task.getReptimes()!=null && task.getReptimes().equals("0")) || task.getReptimes() == null  )){
								task.setReptimes("1");
								task.setReptime(new Date());
								
								//发送提示消息
								processMessage(sessionConfig, sessionConfig.getAgenttimeoutmsg() , sessionConfig.getServicename(),agentUser , agentStatus , task);
								agentUserTaskRes.save(task) ;
							}
						}
					}
				}
			}
		}
	}
	
	@Scheduled(fixedDelay= 5000) // 每5秒执行一次
    public void transferAgentUser() {
		List<SessionConfig> sessionConfigList = ServiceQuene.initSessionConfigList() ;
		if(sessionConfigList!=null && sessionConfigList.size() > 0 && UKDataContext.getContext() != null && UKDataContext.needRunTask()){
			for(SessionConfig sessionConfig : sessionConfigList) {
				sessionConfig = ServiceQuene.initSessionConfig(sessionConfig.getOrgi()) ;
				if(sessionConfig!=null && UKDataContext.getContext() != null && sessionConfig.isTranstip()){
					List<AgentUserTask> agentUserTask = agentUserTaskRes.findByTransfertimeLessThanAndStatusAndOrgi(new Date() , UKDataContext.AgentUserStatusEnum.INTRANS.toString() , sessionConfig.getOrgi()) ;
					for(AgentUserTask task : agentUserTask){		// 超时未回复
						AgentUser agentUser = agentUserRes.findByIdAndOrgi(task.getId(), task.getOrgi()) ;
						if(agentUser!=null){
							agentUser.setRefuse(true);
							ServiceQuene.processAgentUser(agentUser);
						}
					}
				}
			}
		}
	}
	
	/**
	 * 		appid : appid ,
			userid:userid,
			sign:session,
			touser:touser,
			session: session ,
			orgi:orgi,
			username:agentstatus,
			nickname:agentstatus,
			message : message
	 * @param sessionConfig
	 * @param agentUser
	 * @param task
	 */
	
	private void processMessage(SessionConfig sessionConfig , String message, String servicename, AgentUser agentUser , AgentStatus agentStatus , AgentUserTask task){

		MessageOutContent outMessage = new MessageOutContent() ;
		if(!StringUtils.isBlank(message)){
	    	outMessage.setMessage(message);
	    	outMessage.setMessageType(UKDataContext.MediaTypeEnum.TEXT.toString());
	    	outMessage.setCalltype(UKDataContext.CallTypeEnum.OUT.toString());
	    	outMessage.setAgentUser(agentUser);
	    	outMessage.setSnsAccount(null);
	    	
	    	ChatMessage data = new ChatMessage();
	    	if(agentUser!=null){
	    		data.setAppid(agentUser.getAppid());
	    		
	    		data.setUserid(agentUser.getUserid());
	    		data.setUsession(agentUser.getUserid());
	    		data.setTouser(agentUser.getUserid());
	    		data.setOrgi(agentUser.getOrgi());
	    		data.setUsername(agentUser.getUsername());
	    		data.setMessage(message);
	    		
	    		data.setId(UKTools.getUUID());
	    		data.setContextid(agentUser.getContextid());
	    		
	    		data.setAgentserviceid(agentUser.getAgentserviceid());
	    		
	    		data.setCalltype(UKDataContext.CallTypeEnum.OUT.toString());
	    		if(!StringUtils.isBlank(agentUser.getAgentno())){
	    			data.setTouser(agentUser.getUserid());
	    		}
	    		data.setChannel(agentUser.getChannel());
	    		
	    		data.setUsession(agentUser.getUserid());
	    		
	    		outMessage.setContextid(agentUser.getContextid());
	    		outMessage.setFromUser(data.getUserid());
	    		outMessage.setToUser(data.getTouser());
	    		outMessage.setChannelMessage(data);
	    		if(agentStatus!=null){
	        		data.setUsername(agentStatus.getUsername());
	        		outMessage.setNickName(agentStatus.getUsername());
	        	}else {
	        		data.setUsername(servicename);
	        		outMessage.setNickName(servicename);
	        	}
	    		outMessage.setCreatetime(data.getCreatedate());
	    		
	    		/**
	    		 * 保存消息
	    		 */
	    		UKDataContext.getContext().getBean(ChatMessageRepository.class).save(data) ;
	
	    		if(agentUser!=null && !StringUtils.isBlank(agentUser.getAgentno())){	//同时发送消息给双方
	        		NettyClients.getInstance().sendAgentEventMessage(agentUser.getAgentno(), UKDataContext.MessageTypeEnum.MESSAGE.toString(), data);
	        	}

                if(!StringUtils.isBlank(data.getTouser())){
                    OutMessageRouter router = null ;
                    router  = (OutMessageRouter) UKDataContext.getContext().getBean(agentUser.getChannel()) ;
                    if(router!=null){
                        router.handler(data.getTouser(), UKDataContext.MessageTypeEnum.MESSAGE.toString(), agentUser.getAppid(), outMessage);
                    }
                }

	    	}
		}
	}
	
	
	@Scheduled(fixedDelay= 3000 , initialDelay = 20000) // 每三秒 , 加载 标记为执行中的任务何 即将执行的 计划任务
    public void jobDetail() {
		if(UKDataContext.needRunTask()) {
			List<JobDetail> allJob = new ArrayList<JobDetail>();
			Page<JobDetail> readyTaskList = jobDetailRes.findByTaskstatus(UKDataContext.TaskStatusType.READ.getType() , new PageRequest(0,  100)) ;
			allJob.addAll(readyTaskList.getContent()) ;
			Page<JobDetail> planTaskList = jobDetailRes.findByPlantaskAndTaskstatusAndNextfiretimeLessThan(true , UKDataContext.TaskStatusType.NORMAL.getType() ,new Date(), new PageRequest(0,  100)) ;
			allJob.addAll(planTaskList.getContent()) ;
			if(allJob.size()>0){
				for(JobDetail jobDetail : allJob){
					if(CacheHelper.getJobCacheBean().getCacheObject(jobDetail.getId(), jobDetail.getOrgi()) == null) {
						jobDetail.setTaskstatus(UKDataContext.TaskStatusType.QUEUE.getType());
						jobDetailRes.save(jobDetail) ;
						CacheHelper.getJobCacheBean().put(jobDetail.getId(), jobDetail, jobDetail.getOrgi());
						/**
						 * 加入到作业执行引擎
						 */
						new Task(jobDetail, jobDetailRes).start();
					}
				}
			}
			Page<JobDetail> runningTaskList = jobDetailRes.findByTaskstatus(UKDataContext.TaskStatusType.RUNNING.getType() , new PageRequest(0,  100)) ;
			if(runningTaskList!=null && runningTaskList.getContent().size() > 0) {
				for(JobDetail jobDetail : runningTaskList.getContent()){
					if(CacheHelper.getJobCacheBean().getCacheObject(jobDetail.getId(), jobDetail.getOrgi()) == null) {
						jobDetail.setTaskstatus(UKDataContext.TaskStatusType.NORMAL.getType());
						jobDetailRes.save(jobDetail) ;
					}
				}
			}
		}
	}
	
	@Scheduled(fixedDelay= 3000 , initialDelay = 20000) // 每三秒 , 加载 标记为执行中的任务何 即将执行的 计划任务
    public void callOut() {
		if(UKDataContext.model.get("sales")!=null && UKDataContext.needRunTask()) {
			/**
			 * 遍历 队列， 然后推送 名单
			 */
			List<CallCenterAgent> agents = CallOutQuene.service() ;
			for(CallCenterAgent agent : agents) {
				new NamesTask(agent).start();
			}
		}
	}
	
	
	@Scheduled(fixedDelay= 5000 , initialDelay = 20000) // 每三秒 , 加载 标记为执行中的任务何 即将执行的 计划任务
    public void blackListClean() {
		if(UKDataContext.needRunTask()) {
			Page<BlackEntity> blackList = blackListRes.findByEndtimeLessThan(new Date(), new PageRequest(0, 20)) ;
			for(BlackEntity blackEntity : blackList) {
				blackListRes.delete(blackEntity);
				CacheHelper.getSystemCacheBean().getCacheObject(blackEntity.getUserid(),  blackEntity.getOrgi())  ;
			}
		}
	}
	
	@Scheduled(fixedDelay= 3000 , initialDelay = 20000) 
    public void checkInService() throws Exception {
		if(UKDataContext.needRunTask()) {
			Page<AgentService> agentServiceList = agentServiceRes.findAll(new Specification<AgentService>(){
				@Override
				public Predicate toPredicate(Root<AgentService> root, CriteriaQuery<?> query,
						CriteriaBuilder cb) {
					List<Predicate> list = new ArrayList<Predicate>();  
					list.add(cb.lessThan(root.get("createtime").as(Date.class), new Date(System.currentTimeMillis() - 1000 * 60 * 10))) ;
					list.add(cb.equal(root.get("status").as(String.class),UKDataContext.AgentUserStatusEnum.INSERVICE.toString())) ;
					Predicate[] p = new Predicate[list.size()];  

					return cb.and(list.toArray(p));
				}}, new PageRequest(0, 100, Sort.Direction.ASC, "createtime")) ;
			if(agentServiceList.getContent().size()>0) {
				List<AgentService> serviceList = new ArrayList<AgentService>();
				for(AgentService agentService : agentServiceList.getContent()) {
					if(CacheHelper.getAgentUserCacheBean().getCacheObject(agentService.getUserid(), UKDataContext.SYSTEM_ORGI) == null) {
						if(agentService.getCreatetime() == null || (System.currentTimeMillis() - agentService.getCreatetime().getTime()) > 1000 * 60 * 10) {
							agentService.setStatus(UKDataContext.AgentUserStatusEnum.END.toString());
							serviceList.add(agentService) ;
						}
					}
				}
				if(serviceList.size() > 0) {
					agentServiceRepository.save(agentServiceList) ;
				}
			}
		}
	}
	
	@Scheduled(fixedDelay= 10000) // 每十秒执行一次
    public void cleantSocketIOClients() {
		NettyClients.getInstance().clean();
	}

	@Scheduled(fixedDelay= 3000 , initialDelay = 20000) // 每三秒 , 清理在线访客监控
    public void onlineUserClean() {
		OnlineUserUtils.webIMClients.clean();
	}
	
	
	@Scheduled(fixedDelay= 10000 , initialDelay = 20000) // 每三秒 , 清理在线访客监控
    public void onlineUserEsClean() {
		Page<OnlineUser> onlineUserList = onlineUserRes.findAll(new PageRequest(0, 50)) ;
		for(OnlineUser onlineUser : onlineUserList) {
			if(CacheHelper.getOnlineUserCacheBean().getCacheObject(onlineUser.getUserid(), onlineUser.getOrgi()) == null) {
				onlineUser.setStatus(UKDataContext.OnlineUserOperatorStatus.OFFLINE.toString());
				onlineUser.setInvitestatus(UKDataContext.OnlineUserInviteStatus.DEFAULT.toString());
				onlineUser.setBetweentime((int) (new Date().getTime() - onlineUser.getLogintime().getTime()));
				onlineUser.setUpdatetime(new Date());
				onlineUserRes.save(onlineUser) ;
			}
		}
	}
	
	/**
	 * 当前并发采集检查功能 
	 */
	@Scheduled(fixedDelay= 180000 , initialDelay = 20000) // 每分钟执行一次 , 转储通话历史
    public void callOutNames() {
		if(UKDataContext.needRunTask()) {
			CallOutNamesRepository callOutNamesRes = UKDataContext.getContext().getBean(CallOutNamesRepository.class) ;
			Page<CallOutNames> callOutNames ;
			while ((callOutNames = getCallOutNames())!=null && callOutNames.getTotalElements() > 0) {
				for(CallOutNames callOutName : callOutNames.getContent()) {
					/**
					 * 不在缓存中，即为过期任务，需要进行回收
					 */
					if(CacheHelper.getCallOutCacheBean().getCacheObject(callOutName.getDataid(), UKDataContext.SYSTEM_ORGI) == null) {
						callOutNamesRes.delete(callOutName);
						/**
						 * 更新UKDataBean ;
						 */
						if(!StringUtils.isBlank(callOutName.getMetaname()) && !StringUtils.isBlank(callOutName.getDataid())) {
							UKDataBean dataBean = SearchTools.get(callOutName.getMetaname() , callOutName.getDataid()) ;
							if(dataBean!=null && dataBean.getValues()!=null && !StringUtils.isBlank(dataBean.getId())) {
								dataBean.getValues().put("callstatus", UKDataContext.NameStatusTypeEnum.CALLED.toString()) ;
								if(dataBean.getValues().get("calltimes") != null) {
									int calltimes = (int)dataBean.getValues().get("calltimes") ;
									dataBean.getValues().put("calltimes" , calltimes+1) ;
								}else {
									dataBean.getValues().put("calltimes" , 1) ;
								}
								dataBean.getValues().put("apstatus", "false") ;
								SearchTools.updateAndRefresh(dataBean, false);
							}
						}
					}
				}
				if(callOutNames.getTotalElements() == callOutNames.getContent().size()) {
					break ;
				}
			}
			
		}
	}
	/**
	 * 查询需要回收的任务
	 * @return
	 */
	private Page<CallOutNames> getCallOutNames(){
		
		return UKDataContext.getContext().getBean(CallOutNamesRepository.class).findAll(new Specification<CallOutNames>(){
			@Override
			public Predicate toPredicate(Root<CallOutNames> root, CriteriaQuery<?> query,
					CriteriaBuilder cb) {
				List<Predicate> list = new ArrayList<Predicate>();  
				/**
				 * 清理 30分钟之前的任务
				 */
				Calendar calendar = Calendar.getInstance() ;
				calendar.set(Calendar.SECOND, -1800);
				Predicate p1 = cb.lessThan(root.get("createtime").as(Date.class), calendar.getTime());
				list.add(p1);
				Predicate[] p = new Predicate[list.size()];  
		        query.where(cb.and(list.toArray(p)));
		        query.orderBy(cb.desc(root.get("createtime")));
		        return query.getRestriction();
			}},new PageRequest(0,50)) ;
	}
}
